Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Ecl Exception Handling
Description: Introduction to the usage of exceptions in the ecl.Keywords: ecl exceptions
Tutorial Level: INTERMEDIATE
Contents
Exception Types
Standard Exceptions
ecl::StandardException fulfills the general exception type used by the ecl. Note we're just using one class for most exceptions - typically c++ encourages throwing different classes of exceptions for different error types, and we'll probably upgrade to that sometime. Until now though, this has proved conveniently practical and we haven't found any good reason to make things more complicated yet.
Anywhere you wish to throw an ecl::StandardException, throw it by supplying the exception constructor some important information at the point of failure (maybe naive!? if so, please enlighten!).
LOC, the code location macro stamp defined in ecl_errors.
One of the ErrorFlag enum values defined in ecl_errors.
- Optionally an extra string customised to provide further detail.
Typical output from this will be of the form:
Location : /mnt/froody/work/code/cpp/projects/ecl/modules/core/src/tests/exceptions.cpp:154 : /mnt/froody/work/code/cpp/projects/ecl/modules/core/src/tests/exceptions.cpp:151 Flag : There was a configuration error. Detail : Intentionally throwing in debug mode.
If you wish to manually catch and handle them, then you can implement a handler as follows.
Note the use of the flag handler within the if statement.
DataExceptions
Another variant is the data exception which allows an additional data object to be bundled with the exception. This is a templatised class. Note, if you're going to output the error message, the data object needs to be streamable to the standard output (if not, you will get a compile time error).
Rethrowing Exceptions
You can also rethrow a StandardException, useful if you want to track the source of the exception as it goes back up the program heirarchy. This is done by passing the old exception to the constructor call of a new throw.
1 void f(int i) throw(StandardException) {
2 if ( i > 5 ) {
3 throw StandardException(LOC,InvalidInputError,"The maximum input is 5.");
4 }
5 }
6
7 int main() {
8 try {
9 f(6);
10 } catch (StandardException &e) {
11 cout << e.what() << endl;
12 throw StandardException(LOC,e); // Rethrow with a new LOC
13 }
14 }
Disabling Exceptions
Disabling All Exceptions
Exceptions in any of the ecl libraries can be compiled out by simply passing the -DECL_DISABLE_EXCEPTIONS to cmake when compiling the ecl libraries (not your program!). If building in ros you can set this variable in $ROS_ROOT/rosconfig.cmake. Note that this variable is picked up by ecl_config where it sets a macro that is used throughout by the ecl libraries.
When you disable ecl exceptions, all ecl classes are designed in such a way so that they can gracefully fall back to a lower form of error handling.
Debug Only Exceptions
Exceptions can also be enabled exclusively for debug mode (so long as NDEBUG is not defined) with the debug_throw and debug_throw_decl macros. When NDEBUG is defined, the throw will automatically disappear from the program code.
Catching can be done with the usual try-catch blocks, but if you want to pre-process this code away as well, you can use the debug_try and debug_catch macros.
Assertive Exceptions
In addition, you may use the assert_throw and assert_throw_decl macros (a mechanism similar to the run_time_assert function in ecl_errors) as follows: